/*
  LICENSE
  -------
Copyright 2005 Nullsoft, Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer. 

  * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution. 

  * Neither the name of Nullsoft nor the names of its contributors may be used to 
    endorse or promote products derived from this software without specific prior written permission. 
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/


#include "milkdrop.h"
#include "resource.h"
#include "support.h"
#include "configpanel.h"

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <commctrl.h>
//#include <multimon.h>
#include <ddraw.h>
#include <d3d.h>
#include <d3drm.h>

extern CMilkDropObj* pg;		// declared in main.cpp
extern bool g_bDebugOutput;		// declared in support.cpp




typedef struct
{
    int  bpp;
    int  w;
    int  h;
    char name[64];
} VidModeInfo;

td_checkreqs g_d3d_info;
bool		 g_bd3d_info_valid;

#define		MAX_NUM_MONITORS	12
#define		MAX_VIDEO_MODES 144
VidModeInfo VidModeList[MAX_VIDEO_MODES];
int			g_iCurVidMode;	// this is the index in VidModeList[] - NOT valid for the sorted combobox!
int			g_iNumVidModes;	// NOTE: DO NOT AUTOINITIALIZE GLOBAL VARS
int			g_iNumMonitors;
char		g_szMonitorName[MAX_NUM_MONITORS][192];

bool		g_bIgnoreChanges;

// note: initialize these to NULL in WM_INITDIALOG
LPDIRECTDRAW7			g_lpDD;
LPDIRECTDRAWSURFACE7	g_lpDDSConfigFront;
//LPDIRECTDRAWSURFACE7	g_lpDDSConfigBack;
DDCAPS					g_ddcaps;
bool					g_bDDCapsValid;
LPDIRECT3D7				g_lpD3D;				
//LPDIRECT3DDEVICE7		g_lpD3DDev;
//D3DDEVICEDESC7		g_D3DDevDesc;
//bool					g_bD3DCapsValid;


/*
typedef struct
{
	DWORD bpp;
	DWORD rmask;
	DWORD gmask;
	DWORD bmask;
	DWORD amask;
} td_texfmt;

#define		MAX_TEX_FORMATS 100
td_texfmt	g_texfmt[MAX_TEX_FORMATS];
int			g_iNumTexFormats;
*/

/*
typedef struct
{
	LPGUID  lpGuid;
	char	szName[MAX_PATH];
	char	szDesc[MAX_PATH];
	bool	bHW;
} DriverInfo;

#define		MAX_DRIVERS 16

DriverInfo	D3DDriverList[MAX_DRIVERS];
int			g_iCurD3DDriver  = -1;
int			g_iNumD3DDrivers = 0;

DriverInfo	DDrawDriverList[MAX_DRIVERS];
int			g_iCurDDrawDriver  = -1;
int			g_iNumDDrawDrivers = 0;
*/


typedef struct
{
	int		id;
	char	szTip[200];
} td_helpinfo;

static HWND hTooltipWnd = NULL;
static HWND hTooltipWndAdv = NULL;
static HWND hTooltipWndTrans = NULL;

void SetHelpInfo(td_helpinfo *w, int x, int y, char *z) { w[x].id = y; lstrcpy(w[x].szTip, z); };

td_helpinfo		helpinfo     [30];		// Array size MUST equal the # of entries in InitTooltipData()!
td_helpinfo		helpinfoAdv  [16];		// Array size MUST equal the # of entries in InitTooltipData()!
td_helpinfo		helpinfoTrans[ 7];		// Array size MUST equal the # of entries in InitTooltipData()!

void InitTooltipData()
{
	SetHelpInfo(helpinfo, 0,  IDC_RENDERMODE,	 "here you choose how MilkDrop is displayed: fullscreen, in a window, or in your Windows background (\"Desktop Mode\")");
	SetHelpInfo(helpinfo, 1,  IDC_VIDEOMODE,     "this is the resolution (width and height) at which MilkDrop will run.  (for Desktop Mode, it is relative to the size of the desktop.)" );
	SetHelpInfo(helpinfo, 2,  IDC_MONITORS,      "if you have a multiple monitor setup, use this to select which monitor to run on" );
	SetHelpInfo(helpinfo, 3,  IDC_TEXSIZECOMBO,  "the internal image size at which MilkDrop does its computations.  low values are faster, but high values look better.  'Auto' will find the best match for whatever video mode is selected." );
	SetHelpInfo(helpinfo, 4,  IDC_MESHSIZECOMBO, "controls the fineness of the mesh used to generate the motion.  low values are faster, but high values look better." );
	SetHelpInfo(helpinfo, 5,  IDC_MAX_FPS,       "lets you limit MilkDrop's max. frame rate (in frames-per-second)" );
	SetHelpInfo(helpinfo, 6,  IDC_BRIGHT_SLIDER, "allows you to adjust the overall brightness of the images.  If MilkDrop tends to turn bright pink or white, turn the brightness down; if it runs too dark, turn the brightness up." );
	SetHelpInfo(helpinfo, 7,  IDC_CB_HW_BLIT,    "on some video cards, enabling this will make Desktop Mode run much faster; but on others, it will garble the colors and look really bad." );
	SetHelpInfo(helpinfo, 8,  IDC_CB_RGB_FIRST,  "this will fix the color munging in the hardware blit on a handful of video cards" );
	SetHelpInfo(helpinfo, 9,  IDC_CB_YUY2_FIRST, "this also might fix the color munging in the hardware blit on an even tinier handful of video cards" );
	SetHelpInfo(helpinfo, 10, IDC_CB_BURST,      "this *might* speed up the software blit on a tiny handful of video cards (but don't get your hopes up)");
	SetHelpInfo(helpinfo, 11, IDC_FILTER_COLOR,  "allows you to set the \"bluescreen\" or \"filter\" color that MilkDrop will be visible through." );
	SetHelpInfo(helpinfo, 12, IDTRANS,           "allows you to modify behaviors for how frequently the preset changes" );
	SetHelpInfo(helpinfo, 13, IDMORE,	         "change fonts, adjust 3d glasses lens colors, toggle VJ mode..." );
	SetHelpInfo(helpinfo, 14, IDC_CB_PRESSF1,    "if checked, the 'Press F1 for Help' message will no longer appear at startup." );
	SetHelpInfo(helpinfo, 15, IDC_CB_NORATING,   "check this to disable the preset rating system; only do this if you experience unusually long pauses when starting MilkDrop or (*more incriminatingly*) changing preset directories" );
	SetHelpInfo(helpinfo, 16, IDC_CB_DEBUGOUTPUT,"check this to log debug information to a file on disk, to help the author diagnose bugs" );
	SetHelpInfo(helpinfo, 17, IDC_CB_ALWAYS3D,   "check this to always show presets in red-blue stereo 3D" );
	SetHelpInfo(helpinfo, 18, IDC_CB_CLS,        "check this to clear the contents of the graphics window whenever milkdrop starts or you resize the window (otherwise, you'll see the garbage that was in the framebuffer before)" );
	SetHelpInfo(helpinfo, 19, ID_DOCS,           "click here to view the documentation for this program" );
	SetHelpInfo(helpinfo, 20, ID_DEFAULTS,       "click here to restore all original settings" );
	SetHelpInfo(helpinfo, 21, IDC_CB_FIXSLOWTEXT,"check this if your frame rate drops drastically when text is showing.  (Note: this fix sucks up extra video memory!)" );
	SetHelpInfo(helpinfo, 22, IDC_CB_TOP,        "check this to force milkdrop to stay above other windows (when running in windowed mode)" );
	SetHelpInfo(helpinfo, 23, IDC_CB_DBLBUF,     "check this to enable double-buffering for the overlay.  this will prevent page tearing (horizonal breaks in the image), but is slower and uses more video memory.");
	SetHelpInfo(helpinfo, 24, IDC_CB_NOWARN,     "check this to disable all noncritical pop-up warning messageboxes when MilkDrop is starting.");
	SetHelpInfo(helpinfo, 25, IDC_CB_NOWARN2,    "check this to disable all noncritical error/warning messages that sometimes appear in the upper-right corner of the screen.");
	SetHelpInfo(helpinfo, 26, ID_MSG,            "click here to edit the 'custom messages' in the file MILK_MSG.INI (in your WINAMP\\PLUGINS directory).");
	SetHelpInfo(helpinfo, 27, ID_SPRITE,         "click here to edit the sprite definitions in the file MILK_IMG.INI (in your WINAMP\\PLUGINS directory).");
	SetHelpInfo(helpinfo, 28, IDC_XBUS_1,        "determines how the RGB image is copied to system memory to be converted to YUV.  All methods are visually equivalent, but speeds vary from system to system.");
	SetHelpInfo(helpinfo, 29, IDC_XBUS_2,        "this determines how the final YUV image is copied back to video memory after being converted from RGB.  All methods are visually equivalent, but speeds vary from system to system.");
	// note: if you add a control here, be sure to increment the size of the helpinfo[] array by 1

	SetHelpInfo(helpinfoAdv, 0,  IDC_FONT,         "the font face to use for song titles and preset names" );
	SetHelpInfo(helpinfoAdv, 1,  IDC_FONTSIZE,     "the size of the font to use for song titles and preset names" );			
	SetHelpInfo(helpinfoAdv, 2,  IDC_FONTOPTIONS,  "the bold, italic states for song titles and preset names" );
	SetHelpInfo(helpinfoAdv, 3,  IDC_FONT2,        "the font face to use for regular text (menus, notifications, etc.)" );
	SetHelpInfo(helpinfoAdv, 4,  IDC_FONTSIZE2,    "the size of the font to use for regular text (menus, notifications, etc.)" );
	SetHelpInfo(helpinfoAdv, 5,  IDC_FONTOPTIONS2, "the bold, italic states for regular text (menus, notifications, etc.)" );
	SetHelpInfo(helpinfoAdv, 6,  IDC_FONT3,        "the font face to use for graphical song titles" );
	SetHelpInfo(helpinfoAdv, 7,  IDC_FONTSIZE3,    "the size of the font to use for graphical song titles" );
	SetHelpInfo(helpinfoAdv, 8,  IDC_FONTOPTIONS3, "the bold, italic states for graphical song titles" );
	SetHelpInfo(helpinfoAdv, 9,  IDLEFT,           "click here to set the color for the LEFT lens of your color-filtering 3D glasses" );
	SetHelpInfo(helpinfoAdv, 10, IDRIGHT,          "click here to set the color for the RIGHT lens of your color-filtering 3D glasses" );
	SetHelpInfo(helpinfoAdv, 11, IDC_CB_SEPTEXT,   "check this to make MilkDrop display all text in a separate window" );
	SetHelpInfo(helpinfoAdv, 12, IDC_SONGTITLEANIM_DURATION, "lets you specify the duration, in seconds, of the graphical song title animations that pop up when the song changes" );
	SetHelpInfo(helpinfoAdv, 13, IDC_CB_TITLE_ANIMS, "check this to enable the automatica display of animated song titles whenever the song changes" );
	SetHelpInfo(helpinfoAdv, 14, IDC_RAND_TITLE,   "enter the amount of time (in seconds) between the random display of song title animations.  Use -1 to never display them randomly." );
	SetHelpInfo(helpinfoAdv, 15, IDC_RAND_MSG,     "enter the amount of time (in seconds) between the random display of custom messages from the file MILK_MSG.INI in your WINAMP\\PLUGINS directory.  Use -1 to never display them randomly." );
	// note: if you add a control here, be sure to increment the size of the helpinfoAdv[] array by 1

	SetHelpInfo(helpinfoTrans, 0, IDC_BETWEEN_TIME,         "the amount of time (in seconds) between automatic preset changes" );
	SetHelpInfo(helpinfoTrans, 1, IDC_BETWEEN_TIME_RANDOM,  "the additional amount of random time (in seconds) that it may take to automatically change to a new preset" );
	SetHelpInfo(helpinfoTrans, 2, IDC_BLEND_AUTO,           "the amount of time it takes a new preset to fade in, after an automatic preset change" );
	SetHelpInfo(helpinfoTrans, 3, IDC_BLEND_USER,           "the amount of time it takes a new preset to fade in, after the user presses SPACEBAR or loads a specific preset from the load menu" );
	SetHelpInfo(helpinfoTrans, 4, IDC_HARDCUT_BETWEEN_TIME, "the target amount of time that must pass, after a hard cut, before a beat (in the music) can cause the next hard cut." );
	SetHelpInfo(helpinfoTrans, 5, IDC_HARDCUT_LOUDNESS,     "controls the sensitivity of the beat detection; at 'min', most beats cause a hard cut; at 'max', only the very loudest beats will." );
	SetHelpInfo(helpinfoTrans, 6, IDC_CB_HARDCUTS,          "determines whether or not hard cuts are allowed" );
	// note: if you add a control here, be sure to increment the size of the helpinfoTrans[] array by 1
}


void DoColors(HWND hwnd, int *r, int *g, int *b)
{
	static COLORREF acrCustClr[16]; 

	CHOOSECOLOR cc;
	ZeroMemory(&cc, sizeof(CHOOSECOLOR));
	cc.lStructSize = sizeof(CHOOSECOLOR);
	cc.hwndOwner = hwnd;//NULL;//hSaverMainWindow;
	cc.Flags = CC_RGBINIT | CC_FULLOPEN;
	cc.rgbResult = RGB(*r,*g,*b);
	cc.lpCustColors = (LPDWORD)acrCustClr;
	if (ChooseColor(&cc))
	{
		*r = GetRValue(cc.rgbResult);
		*g = GetGValue(cc.rgbResult);
		*b = GetBValue(cc.rgbResult);
	}
}



HRESULT WINAPI EnumDisplayModesCallback(
  LPDDSURFACEDESC2 lpDDSurfaceDesc,  
  LPVOID lpContext                  
)
{
    int w = lpDDSurfaceDesc->dwWidth;
    int h = lpDDSurfaceDesc->dwHeight;
    int bpp = lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount;

	// don't even bother list 8bpp modes
	if (bpp == 8)
	{
	    return DDENUMRET_OK;
	}

    char modemsg[512];
    sprintf(modemsg, "video mode: %4dx%4dx%4d, linearsize=%5d, Rmask=%08x, Gmask=%08x, Bmask=%08x", 
        lpDDSurfaceDesc->dwWidth, 
        lpDDSurfaceDesc->dwHeight, 
        lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount, 
        lpDDSurfaceDesc->dwLinearSize,
        lpDDSurfaceDesc->ddpfPixelFormat.dwRBitMask,
        lpDDSurfaceDesc->ddpfPixelFormat.dwGBitMask,
        lpDDSurfaceDesc->ddpfPixelFormat.dwBBitMask
    );

	/*if (g_iNumTexFormats > 0 && !CheckPixelFormatForTextures(lpDDSurfaceDesc))
	{
		// note: this worked for the GeForce 2 MX; it screened out the 24-bit-color modes, which would normally bomb
		//
		lstrcat(modemsg, " - REJECTED due to texture format");
	}
	else*/ 
	/*
	if (g_bD3DCapsValid && bpp==16 && !(g_D3DDevDesc.dwDeviceRenderBitDepth & DDBD_16))
		lstrcat(modemsg, " - REJECTED because D3D device doesn't support 16-bit rendering");
	else if (g_bD3DCapsValid && bpp==24 && !(g_D3DDevDesc.dwDeviceRenderBitDepth & DDBD_24))
		lstrcat(modemsg, " - REJECTED because D3D device doesn't support 24-bit rendering");
	else if (g_bD3DCapsValid && bpp==32 && !(g_D3DDevDesc.dwDeviceRenderBitDepth & DDBD_32))
		lstrcat(modemsg, " - REJECTED because D3D device doesn't support 32-bit rendering");
	*/
	if (g_bd3d_info_valid && bpp==16 && !g_d3d_info.b16BitOk)
		lstrcat(modemsg, " - REJECTED because card can't do D3D in 16-bit color");
	else if (g_bd3d_info_valid && bpp==24 && !g_d3d_info.b24BitOk)
		lstrcat(modemsg, " - REJECTED because card can't do D3D in 24-bit color");
	else if (g_bd3d_info_valid && bpp==32 && !g_d3d_info.b32BitOk)
		lstrcat(modemsg, " - REJECTED because card can't do D3D in 32-bit color");
	else
	{
		if (g_iNumVidModes >= MAX_VIDEO_MODES-1)     // max out at 100
		{
			pg->dumpmsg("*************TOO MANY VIDEO MODES*************");
			return DDENUMRET_CANCEL ;
		}

		// determine # of green bits for 16-bit color modes
		/*
		int gmask, gbits=0;
		gmask = lpDDSurfaceDesc->ddpfPixelFormat.dwGBitMask;
		while (gmask>0) { gbits += gmask & 1; gmask >>= 1; }
		*/

		/*
		if (pg->m_bFirstRun)
		{
			// try to find best default video mode
			if (w == pg->m_nWidthFS && h == pg->m_nHeightFS)
			{
				// try to find the 16-bit version of the mode, but if it doesn't exist,
				// settle for another bit depth (but same W+H).
				if (g_iCurVidMode == -1)
				{
					g_iCurVidMode = g_iNumVidModes;
				}
				else if (bpp == pg->m_nDispBits && VidModeList[g_iCurVidMode].bpp != pg->m_nDispBits)
				{
					g_iCurVidMode = g_iNumVidModes;
				}
			}

		}
		else
		{
			// if this video mode is the one they picked before, we need
			// to remember that so it shows up as selected in the combobox.
			if (w == pg->m_nWidthFS &&
				h == pg->m_nHeightFS &&
				bpp == pg->m_nDispBits)
			{
				g_iCurVidMode = g_iNumVidModes;
			}
		}
		*/

		// save mode info in VidModeList[]
		//VidModeList[g_iNumVidModes].b555mode = (gbits == 5);   // regular = 5/6/5, fucked = (1)/5/5/5
		VidModeList[g_iNumVidModes].w        = w;
		VidModeList[g_iNumVidModes].h        = h;
		VidModeList[g_iNumVidModes].bpp      = bpp;
		sprintf(VidModeList[g_iNumVidModes].name, " %2d-bit color,  %4d x %4d pixels  %s", 
				bpp,
				w, 
				h,
				(bpp==32) ? "[recommended]" : ""
			);

		g_iNumVidModes++;
	}

    pg->dumpmsg(modemsg);

    return DDENUMRET_OK;
}


/*
BOOL WINAPI DDEnumCallbackExForConfigPanel(
  GUID FAR *lpGUID,    
  LPSTR     lpDriverDescription, 
  LPSTR     lpDriverName,        
  LPVOID    lpContext,           
  HMONITOR  hm        
)
{
	DDrawDriverList[g_iNumDDrawDrivers].lpGuid = lpGUID;
	lstrcpy( &DDrawDriverList[g_iNumDDrawDrivers].szName[0], lpDriverName );
	lstrcpy( &DDrawDriverList[g_iNumDDrawDrivers].szDesc[0], lpDriverDescription );

	if (lstrcmp(pg->m_szDDrawDriverName, lpDriverName) == 0 &&
	    lstrcmp(pg->m_szDDrawDriverDesc, lpDriverDescription) == 0)
	{
		g_iCurDDrawDriver = g_iNumDDrawDrivers;
	}

	if( ++g_iNumDDrawDrivers >= MAX_DRIVERS )
		return 0;
	
	return 1;
}
*/



/*
HRESULT WINAPI enumDeviceFuncForConfigPanel(
	LPGUID			pGuid, 
	PSTR			pDeviceDescription,
	LPSTR			pDeviceName, 
	LPD3DDEVICEDESC pHWDesc, 
	LPD3DDEVICEDESC pHELDesc, 
	VOID*			pContext )
{
	// Decide which device description we should consult
	LPD3DDEVICEDESC pDesc = pHWDesc->dcmColorModel ? pHWDesc : pHELDesc;
	
	// Record this driver's info
	D3DDriverList[g_iNumD3DDrivers].lpGuid = pGuid;
	lstrcpy( &D3DDriverList[g_iNumD3DDrivers].szName[0], pDeviceName );
	lstrcpy( &D3DDriverList[g_iNumD3DDrivers].szDesc[0], pDeviceDescription );
	D3DDriverList[g_iNumD3DDrivers].bHW = (pDesc == pHWDesc);

	if (lstrcmp(pg->m_szD3DDriverName, pDeviceName) == 0 &&
	    lstrcmp(pg->m_szD3DDriverDesc, pDeviceDescription) == 0)
	{
		g_iCurD3DDriver = g_iNumD3DDrivers;
	}

	if( ++g_iNumD3DDrivers >= MAX_DRIVERS )
		return D3DENUMRET_CANCEL;
	
	return D3DENUMRET_OK;
}
*/

/*
int CALLBACK EnumFontFamExProc(
  ENUMLOGFONTEX *lpelfe,    // logical-font data
  NEWTEXTMETRICEX *lpntme,  // physical-font data
  DWORD FontType,           // type of font
  LPARAM lParam             // application-defined data
)
{
	SendMessage( GetDlgItem( (HWND)lParam, IDC_FONT ), CB_ADDSTRING, 0, (LPARAM)(lpelfe->elfFullName));
	return 1;
}
*/

/*
BOOL CALLBACK MonitorEnumProc(
  HMONITOR hMonitor,  // handle to display monitor
  HDC hdcMonitor,     // handle to monitor DC
  LPRECT lprcMonitor, // monitor intersection rectangle
  LPARAM dwData       // data
)
{
	g_iNumMonitors++;
	char buf[256];
	sprintf(buf, " Monitor #%d ", g_iNumMonitors);
	if (g_iNumMonitors==1)
		lstrcat(buf, " [primary]");
	SendMessage( GetDlgItem( (HWND)dwData, IDC_MONITORS ), CB_ADDSTRING, g_iNumMonitors-1, (LPARAM)(buf));
	return TRUE;
}
*/


BOOL WINAPI DDEnumCallbackEx(
  GUID FAR *lpGUID,    
  LPSTR     lpDriverDescription, 
  LPSTR     lpDriverName,        
  LPVOID    lpContext,           
  HMONITOR  hm        
)
{
	lstrcpy(g_szMonitorName[g_iNumMonitors], lpDriverName);

	char buf[512];
	sprintf(buf, " %s [%s] ", lpDriverName, lpDriverDescription);
	SendMessage( GetDlgItem( (HWND)lpContext, IDC_MONITORS ), CB_ADDSTRING, g_iNumMonitors, (LPARAM)(buf));

	g_iNumMonitors++;
	
	return (g_iNumMonitors==MAX_NUM_MONITORS) ? FALSE : TRUE;
}


int CALLBACK EnumFontsProc(
  CONST LOGFONT *lplf,     // logical-font data
  CONST TEXTMETRIC *lptm,  // physical-font data
  DWORD dwType,            // font type
  LPARAM lpData            // application-defined data
)
{
	SendMessage( GetDlgItem( (HWND)lpData, IDC_FONT ), CB_ADDSTRING, 0, (LPARAM)(lplf->lfFaceName));
	SendMessage( GetDlgItem( (HWND)lpData, IDC_FONT2), CB_ADDSTRING, 0, (LPARAM)(lplf->lfFaceName));
	SendMessage( GetDlgItem( (HWND)lpData, IDC_FONT3), CB_ADDSTRING, 0, (LPARAM)(lplf->lfFaceName));
	return 1;
}


void Refresh(HWND hwnd)
{

	// 1. video mode sel. box:
	SendMessage( GetDlgItem( hwnd, IDC_VIDEOMODE ), CB_RESETCONTENT, 0, 0);
	if (pg->m_bDesktopMode)
	{
		// use the combobox to list the rendering sizes (full, half, quarter)
		SendMessage( GetDlgItem( hwnd, IDC_VIDEOMODE ), CB_ADDSTRING, 0, (LPARAM)" full resolution (slowest; best quality) ");
		SendMessage( GetDlgItem( hwnd, IDC_VIDEOMODE ), CB_ADDSTRING, 1, (LPARAM)" half resolution ");
		SendMessage( GetDlgItem( hwnd, IDC_VIDEOMODE ), CB_ADDSTRING, 2, (LPARAM)" quarter resolution (fast but coarse) ");
		SendMessage( GetDlgItem( hwnd, IDC_VIDEOMODE ), CB_SETCURSEL, pg->m_nDesktopProcSize, 0);
	}
	else
	{
		// use the combobox to list video modes
		if (pg->m_bWindowed)
		{
			SendMessage( GetDlgItem( hwnd, IDC_VIDEOMODE ), CB_ADDSTRING, 0, (LPARAM)" n/a ");
			SendMessage( GetDlgItem( hwnd, IDC_VIDEOMODE ), CB_SETCURSEL, 0, 0);
		}
		else	// fullscreen
		{
			// use .name, which shows bit depth, width, and height.
			for (int i=0; i<g_iNumVidModes; i++)
			{
				int nPos = SendMessage( GetDlgItem( hwnd, IDC_VIDEOMODE ), CB_ADDSTRING, 0, (LPARAM)VidModeList[i].name);
				SendMessage( GetDlgItem( hwnd, IDC_VIDEOMODE ), CB_SETITEMDATA, nPos, i);
			}

			// now set selection
			for (i=0; i<g_iNumVidModes; i++)
			{
				int vidmode = SendMessage( GetDlgItem( hwnd, IDC_VIDEOMODE ), CB_GETITEMDATA, i, 0);

				if (VidModeList[vidmode].w == pg->m_nWidth &&
					VidModeList[vidmode].h == pg->m_nHeight &&
					(pg->m_bWindowed || VidModeList[vidmode].bpp == pg->m_nDispBits))	// ignore bit depth matching if in Windowed mode
				{
					SendMessage( GetDlgItem( hwnd, IDC_VIDEOMODE ), CB_SETCURSEL, i, 0);
				}
			}
		}
	}
	
	EnableWindow(GetDlgItem( hwnd, IDC_VIDEOMODE), !pg->m_bWindowed);
	EnableWindow(GetDlgItem( hwnd, IDC_CB_HW_BLIT), pg->m_bDesktopMode && pg->m_bMMX);
	EnableWindow(GetDlgItem( hwnd, IDC_FILTER_COLOR), pg->m_bDesktopMode);
	//EnableWindow(GetDlgItem( hwnd, IDC_CB_BURST), pg->m_bDesktopMode && !pg->m_bHardwareDesktopBlit);
	EnableWindow(GetDlgItem( hwnd, IDC_CB_RGB_FIRST), pg->m_bDesktopMode);// && pg->m_bHardwareDesktopBlit);
	EnableWindow(GetDlgItem( hwnd, IDC_CB_YUY2_FIRST), pg->m_bDesktopMode);// && pg->m_bHardwareDesktopBlit);
	EnableWindow(GetDlgItem( hwnd, IDC_CB_DBLBUF), pg->m_bDesktopMode);
	EnableWindow(GetDlgItem( hwnd, IDC_XBUS_TEXT1), pg->m_bDesktopMode && !pg->m_bHardwareDesktopBlit);
	EnableWindow(GetDlgItem( hwnd, IDC_XBUS_TEXT2), pg->m_bDesktopMode && !pg->m_bHardwareDesktopBlit);
	EnableWindow(GetDlgItem( hwnd, IDC_XBUS_TEXT3), pg->m_bDesktopMode && !pg->m_bHardwareDesktopBlit);
	EnableWindow(GetDlgItem( hwnd, IDC_XBUS_1), pg->m_bDesktopMode && !pg->m_bHardwareDesktopBlit);
	EnableWindow(GetDlgItem( hwnd, IDC_XBUS_2), pg->m_bDesktopMode && !pg->m_bHardwareDesktopBlit);

	ShowWindow(GetDlgItem(hwnd, IDC_BRIGHT_SLIDER), !pg->m_bAutoGamma);
	ShowWindow(GetDlgItem(hwnd, IDC_T1), !pg->m_bAutoGamma);
	ShowWindow(GetDlgItem(hwnd, IDC_T2), !pg->m_bAutoGamma);
	ShowWindow(GetDlgItem(hwnd, IDC_T3), !pg->m_bAutoGamma);
	ShowWindow(GetDlgItem(hwnd, IDC_T4), !pg->m_bAutoGamma);
	ShowWindow(GetDlgItem(hwnd, IDC_T5), !pg->m_bAutoGamma);
}


void ReadBitDepthCombo(HWND hwnd)
{
	if (pg->m_bDesktopMode)
	{
		// desktop rendering size combo
		int t = SendMessage( GetDlgItem( hwnd, IDC_VIDEOMODE ), CB_GETCURSEL, 0, 0);
		if (t != CB_ERR && t>=0 && t<=2) pg->m_nDesktopProcSize = t;
	}
	else if (!pg->m_bWindowed)	// fullscreen:
	{
		int t = SendMessage( GetDlgItem( hwnd, IDC_VIDEOMODE ), CB_GETCURSEL, 0, 0);
		if (t == CB_ERR) t = 0;
		g_iCurVidMode	= SendMessage( GetDlgItem( hwnd, IDC_VIDEOMODE ), CB_GETITEMDATA, t, 0);
		pg->m_nWidth	= VidModeList[g_iCurVidMode].w;
		pg->m_nHeight	= VidModeList[g_iCurVidMode].h;
		pg->m_nDispBits	= VidModeList[g_iCurVidMode].bpp;
	}
}


BOOL CALLBACK ConfigDialogProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
	char buf[256];
	char buf2[64];
	IdentifyWindowsMessage(msg, buf2);
	sprintf(buf, "CfgDlgProc: hwnd=%08x, msg=%08x, wParam=%08x, lParam=%08x [%s]", hwnd, msg, wParam, lParam, buf2);
	pg->dumpmsg(buf);
	//OutputDebugString(buf);

	switch (msg)
	{
	case WM_NOTIFY: 
		{ 
			LPNMHDR t=(LPNMHDR)lParam; 
			if (t->code == TTN_POP) 
			{ 
				SendMessage(hTooltipWnd,TTM_SETDELAYTIME,TTDT_INITIAL,1000); 
				SendMessage(hTooltipWnd,TTM_SETDELAYTIME,TTDT_RESHOW,1000); 
			} 
		}
		break;

	case WM_DESTROY:
		if (IsWindow(hTooltipWnd)) 
		{ 
			DestroyWindow(hTooltipWnd); 
			hTooltipWnd=NULL; 
		}
		break;

    case WM_INITDIALOG:
		{ 

			// do initialization of global variables HERE.
			// do initialization of global variables HERE.
			// do initialization of global variables HERE.
			// do initialization of global variables HERE.
			// do initialization of global variables HERE.
			g_iCurVidMode	= -1;
			g_iNumVidModes	= 0;
			g_iNumMonitors  = 1;
			//g_iNumTexFormats = 0;
			lstrcpy(g_szMonitorName[0], "[don't use multimon]");
			
			g_lpDD				= NULL;
			g_lpDDSConfigFront	= NULL;
			g_bDDCapsValid		= false;
			g_lpD3D				= NULL;				
			//g_lpD3DDev		= NULL;
			//g_bD3DCapsValid	= false;
			g_bd3d_info_valid	= false;
			g_bIgnoreChanges	= true;

			InitTooltipData();

			// do initialization of global variables HERE.
			// do initialization of global variables HERE.
			// do initialization of global variables HERE.
			// do initialization of global variables HERE.
			// do initialization of global variables HERE.


			HRESULT hr;
			
			//-------------- DirectDraw video mode detection ---------------------
			if (!ConfigPanel_DirectX_Init(hwnd))
			{
				int id=LOWORD(wParam);
				EndDialog(hwnd,id);
			}
			
			pg->dumpmsg("calling EnumDisplayModes() for config panel...");
			g_iNumVidModes = 0;
			hr = g_lpDD->EnumDisplayModes(0, NULL, NULL, &EnumDisplayModesCallback);
			if (hr != DD_OK || g_iNumVidModes<0) 
			{
				sprintf(buf, "couldn't enumerate any video modes!");
				pg->dumpmsg(buf); 
				MessageBox( NULL, buf, "MILKDROP ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST );

				int id=LOWORD(wParam);
				EndDialog(hwnd,id);
			}
			// combo box contents and selection will be set in Refresh()

			if (g_iCurVidMode == -1)
			{
				g_iCurVidMode = 0;
			}

			//-------------- cleanup ---------------------
			
			ConfigPanel_DirectX_Cleanup();

			// -------------- render mode combo box --------------

			SendMessage( GetDlgItem( hwnd, IDC_RENDERMODE ), CB_ADDSTRING, 0, (LPARAM)" Fullscreen ");
			SendMessage( GetDlgItem( hwnd, IDC_RENDERMODE ), CB_ADDSTRING, 1, (LPARAM)" Windowed ");
			SendMessage( GetDlgItem( hwnd, IDC_RENDERMODE ), CB_ADDSTRING, 2, (LPARAM)" Desktop Mode (using overlays) ");
			if (pg->m_bWindowed && !pg->m_bDesktopMode)
				SendMessage( GetDlgItem( hwnd, IDC_RENDERMODE ), CB_SETCURSEL, 1, 0);
			else if (!pg->m_bWindowed && pg->m_bDesktopMode)
				SendMessage( GetDlgItem( hwnd, IDC_RENDERMODE ), CB_SETCURSEL, 2, 0);
			else
				SendMessage( GetDlgItem( hwnd, IDC_RENDERMODE ), CB_SETCURSEL, 0, 0);

			//-------------- texture size combo box ---------------------

			for (int i=0; i<4; i++)
			{
				int size = (int)pow(2, i+8);
				sprintf(buf, " %4d x %4d ", size, size);
				int nPos = SendMessage( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_ADDSTRING, 0, (LPARAM)buf);
				SendMessage( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_SETITEMDATA, nPos, size);
			}

			// throw the "Auto" option in there
			int nPos = SendMessage( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_ADDSTRING, 0, (LPARAM)" Auto ");
			SendMessage( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_SETITEMDATA, nPos, -1);
			
			for (i=0; i<4+1; i++)
			{
				int size = SendMessage( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_GETITEMDATA, i, 0);
				if (size == pg->m_nTexSize)
				{
					SendMessage( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_SETCURSEL, i, 0);
				}
			}

			//-------------- mesh size combo box ---------------------
			HWND meshcombo = GetDlgItem( hwnd, IDC_MESHSIZECOMBO );
			nPos = SendMessage(meshcombo , CB_ADDSTRING, 0, (LPARAM)"  8 x  6 FAST ");
			SendMessage( meshcombo, CB_SETITEMDATA, nPos, 8);
			nPos = SendMessage( meshcombo, CB_ADDSTRING, 0, (LPARAM)" 16 x 12 fast ");
			SendMessage( meshcombo, CB_SETITEMDATA, nPos, 16);
			nPos = SendMessage( meshcombo, CB_ADDSTRING, 0, (LPARAM)" 24 x 18 ");
			SendMessage( meshcombo, CB_SETITEMDATA, nPos, 24);
			nPos = SendMessage( meshcombo, CB_ADDSTRING, 0, (LPARAM)" 32 x 24 slow");
			SendMessage( meshcombo, CB_SETITEMDATA, nPos, 32);
			nPos = SendMessage( meshcombo, CB_ADDSTRING, 0, (LPARAM)" 40 x 30 SLOW ");
			SendMessage( meshcombo, CB_SETITEMDATA, nPos, 40);
			nPos = SendMessage( meshcombo, CB_ADDSTRING, 0, (LPARAM)" 48 x 36 SLOW ");
			SendMessage( meshcombo, CB_SETITEMDATA, nPos, 48);

			int nCount = SendMessage( GetDlgItem( hwnd, IDC_MESHSIZECOMBO ), CB_GETCOUNT, 0, 0);
			for (i=0; i<nCount; i++)
			{
				int size = SendMessage( GetDlgItem( hwnd, IDC_MESHSIZECOMBO ), CB_GETITEMDATA, i, 0);
				if (size == pg->m_nGridX)
				{
					SendMessage( GetDlgItem( hwnd, IDC_MESHSIZECOMBO ), CB_SETCURSEL, i, 0);
				}
			}

			//---------------------------------------------------------------

			// multiple monitor detection
			//EnumDisplayMonitors( NULL, NULL, MonitorEnumProc, (LPARAM)hwnd );
			SendMessage( GetDlgItem( hwnd, IDC_MONITORS ), CB_ADDSTRING, 0, (LPARAM)"[don't use multimon]");
			DirectDrawEnumerateEx( DDEnumCallbackEx, (LPVOID)hwnd, DDENUM_ATTACHEDSECONDARYDEVICES );
			
			// set selection
			SendMessage( GetDlgItem( hwnd, IDC_MONITORS ), CB_SETCURSEL, 0, 0);
			for (i=0; i<g_iNumMonitors; i++)
				if (lstrcmp(g_szMonitorName[i], pg->m_szMonitorName)==0)
					SendMessage( GetDlgItem( hwnd, IDC_MONITORS ), CB_SETCURSEL, i, 0);

			//---------fps limit combo box--------------
			
			SendMessage( GetDlgItem( hwnd, IDC_MAX_FPS ), CB_ADDSTRING, 0, (LPARAM)" unlimited ");
			SendMessage( GetDlgItem( hwnd, IDC_MAX_FPS ), CB_SETITEMDATA, 0, -1);
			for (i=10; i<=60; i++)
			{
				sprintf(buf, " %d ", i);
				SendMessage( GetDlgItem( hwnd, IDC_MAX_FPS ), CB_ADDSTRING, i-9, (LPARAM)buf);
				SendMessage( GetDlgItem( hwnd, IDC_MAX_FPS ), CB_SETITEMDATA, i-9, i);
			}

			if (pg->m_nFpsLimit >= 10 && pg->m_nFpsLimit <= 60)
				SendMessage( GetDlgItem( hwnd, IDC_MAX_FPS ), CB_SETCURSEL, (pg->m_nFpsLimit - 9), 0);
			else
				SendMessage( GetDlgItem( hwnd, IDC_MAX_FPS ), CB_SETCURSEL, 0, 0);

			//---------16-bit brightness slider--------------

			SendMessage( GetDlgItem( hwnd, IDC_BRIGHT_SLIDER), TBM_SETRANGEMIN,
				FALSE, (LPARAM)(0) );
			SendMessage( GetDlgItem( hwnd, IDC_BRIGHT_SLIDER), TBM_SETRANGEMAX,
				FALSE, (LPARAM)(4) );
			SendMessage( GetDlgItem( hwnd, IDC_BRIGHT_SLIDER), TBM_SETPOS,
				TRUE, (LPARAM)(pg->m_n16BitGamma) );
			for (i=0; i<5; i++)
				SendMessage( GetDlgItem( hwnd, IDC_BRIGHT_SLIDER), TBM_SETTIC, 0, i);

			//---------xbus combo boxes--------------
			
			SendMessage( GetDlgItem( hwnd, IDC_XBUS_1 ), CB_ADDSTRING, 0, (LPARAM)"copy using mmx");
			SendMessage( GetDlgItem( hwnd, IDC_XBUS_1 ), CB_ADDSTRING, 1, (LPARAM)"blit using directx");
			SendMessage( GetDlgItem( hwnd, IDC_XBUS_1 ), CB_ADDSTRING, 2, (LPARAM)"skip it(read vid.mem directly)");
			SendMessage( GetDlgItem( hwnd, IDC_XBUS_2 ), CB_ADDSTRING, 0, (LPARAM)"copy using mmx");
			SendMessage( GetDlgItem( hwnd, IDC_XBUS_2 ), CB_ADDSTRING, 1, (LPARAM)"blit using directx");
			SendMessage( GetDlgItem( hwnd, IDC_XBUS_2 ), CB_ADDSTRING, 2, (LPARAM)"skip it(write vid.mem directly)");

			SendMessage( GetDlgItem( hwnd, IDC_XBUS_1 ), CB_SETCURSEL, pg->m_xBusMode[0], 0);
			SendMessage( GetDlgItem( hwnd, IDC_XBUS_2 ), CB_SETCURSEL, pg->m_xBusMode[1], 0);
			//---------------------------------------------------------------
			
			pg->dumpmsg("Setting initial states of controls for config panel...");

			// append debug output filename to the checkbox's text
			GetWindowText( GetDlgItem(hwnd, IDC_CB_DEBUGOUTPUT), buf, 256);
			lstrcat(buf, DEBUGFILE);
			SetWindowText( GetDlgItem(hwnd, IDC_CB_DEBUGOUTPUT), buf);

			// info string
			sprintf(buf, "%s by Ryan Geiss\r\ncopyright(c) 2001 Nullsoft, Inc.", DLLDESC);
			SetWindowText( GetDlgItem(hwnd, IDC_INFO), buf);
			sprintf(buf, "%s - Config Panel", DLLDESC);
			SetWindowText( hwnd, buf );

			// set checkboxes
			CheckDlgButton(hwnd, IDC_CB_DEBUGOUTPUT, g_bDebugOutput);
			CheckDlgButton(hwnd, IDC_CB_PRESSF1, (!pg->m_bShowPressF1ForHelp));
			//CheckDlgButton(hwnd, IDC_CB_TOOLTIPS, pg->m_bShowMenuToolTips);
			CheckDlgButton(hwnd, IDC_CB_ALWAYS3D, pg->m_bAlways3D);
			CheckDlgButton(hwnd, IDC_CB_FIXSLOWTEXT, pg->m_bFixSlowText);
			CheckDlgButton(hwnd, IDC_CB_TOP, pg->m_bAlwaysOnTop);
			CheckDlgButton(hwnd, IDC_CB_CLS, !pg->m_bClearScreenAtStartup);
			CheckDlgButton(hwnd, IDC_CB_NOWARN, pg->m_bWarningsDisabled);
			CheckDlgButton(hwnd, IDC_CB_NOWARN2, pg->m_bWarningsDisabled2);
			//CheckDlgButton(hwnd, IDC_CB_PINKFIX, pg->m_bFixPinkBug);
			CheckDlgButton(hwnd, IDC_CB_WINDOWED, pg->m_bWindowed);
			CheckDlgButton(hwnd, IDC_CB_DESKTOP, pg->m_bDesktopMode);
			CheckDlgButton(hwnd, IDC_CB_NORATING, !pg->m_bEnableRating);
			CheckDlgButton(hwnd, IDC_CB_HW_BLIT, pg->m_bHardwareDesktopBlit);
			//CheckDlgButton(hwnd, IDC_CB_BURST, pg->m_bDesktopModeSkipBurstCopy);
			CheckDlgButton(hwnd, IDC_CB_RGB_FIRST, pg->m_bTryRGBOverlayFirst);
			CheckDlgButton(hwnd, IDC_CB_YUY2_FIRST, pg->m_bTryYUY2OverlayFirst);
			CheckDlgButton(hwnd, IDC_CB_DBLBUF, pg->m_bDesktopModeDoubleBuffered);
			CheckDlgButton(hwnd, IDC_CB_AUTOGAMMA, pg->m_bAutoGamma);
			
			/*
			SendMessage( GetDlgItem( hwnd, IDC_GAMMA_SLIDER), TBM_SETRANGEMIN,
				FALSE, (LPARAM)(0) );
			SendMessage( GetDlgItem( hwnd, IDC_GAMMA_SLIDER), TBM_SETRANGEMAX,
				FALSE, (LPARAM)(100) );
			SendMessage( GetDlgItem( hwnd, IDC_GAMMA_SLIDER), TBM_SETPOS,
				TRUE, (LPARAM)(gamma) );

			CheckDlgButton(hwnd, IDC_AUTOMIN, AUTOMIN);
  
			SetWindowText( GetDlgItem( hwnd, IDC_TEXT2 ), "You should adjust the vertical screen size (and/or video mode) until you get 28-30 frames per second - no more! (for best look).  You should also set the plugin priority to 'Normal' so Winamp is sure to update the wave every frame." );
			::EnableWindow(GetDlgItem( hwnd, IDC_SOUNDON ), false );
			*/			

			// Initialize Tooltip window
			pg->dumpmsg("initializing tooltips...");
			int x;
			hTooltipWnd = CreateWindow(TOOLTIPS_CLASS,(LPCSTR)NULL,TTS_ALWAYSTIP,
				CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, hwnd,NULL,GetModuleHandle(NULL),NULL);
			SendMessage(hTooltipWnd,TTM_SETDELAYTIME,TTDT_AUTOPOP,8000);
			SendMessage(hTooltipWnd,TTM_SETDELAYTIME,TTDT_INITIAL,750);
			SendMessage(hTooltipWnd,TTM_SETDELAYTIME,TTDT_RESHOW,750);

			for (x = 0; x < sizeof(helpinfo)/sizeof(helpinfo[0]); x ++) 
			{
				TOOLINFO ti; 
				ti.cbSize = sizeof(ti); 
				ti.uFlags = TTF_SUBCLASS|TTF_IDISHWND;
				ti.uId=(unsigned int)GetDlgItem(hwnd,helpinfo[x].id); 
				ti.hwnd=hwnd; 
				ti.lpszText = helpinfo[x].szTip;
				SendMessage(hTooltipWnd,TTM_ADDTOOL,0,(LPARAM) &ti);
			}

			// update the video mode combo box:
			Refresh(hwnd);

			SetFocus(hwnd);

			pg->dumpmsg("---config dialog init complete---");

			g_bIgnoreChanges = false;
			
			//return TRUE;
		}
		break;		// case WM_INITDIALOG

	/*
	case WM_KEYDOWN:
		if (wParam == VK_ESCAPE)
			EndDialog(hwnd,IDCANCEL);
		break;
	*/

    case WM_COMMAND:
		{
			int id = LOWORD(wParam);
			int t;
			switch(id)
			{
			
			case IDC_RENDERMODE:
				{
					if (!g_bIgnoreChanges)
					{
						g_bIgnoreChanges = true;

						ReadBitDepthCombo(hwnd);	// sets (width, height, and dispbits) if in windowed/fullscreen mode, or (pg->m_nDesktopProcSize) if in desktop mode

						int t = SendMessage( GetDlgItem( hwnd, IDC_RENDERMODE ), CB_GETCURSEL, 0, 0);				
						if (t != CB_ERR)
						{
							bool bOldDesktopMode = pg->m_bDesktopMode;
							bool bOldWindowed    = pg->m_bWindowed;

							switch(t)
							{
							case 0:		// fullscreen
								pg->m_bDesktopMode = false;
								pg->m_bWindowed    = false;
								break;
							case 1:		// windowed
								pg->m_bDesktopMode = false;
								pg->m_bWindowed    = true;
								break;
							case 2:		// desktop mode
								pg->m_bDesktopMode = true;
								pg->m_bWindowed    = false;
								break;
							}

							if (pg->m_bDesktopMode && !bOldDesktopMode)
							{
								// entering desktop mode -> check caps here!
								char buf[512];

								if (!pg->m_bMMX)
								{
									// check the 'USE HW BLIT' checkbox
									pg->m_bHardwareDesktopBlit = true;
									CheckDlgButton(hwnd, IDC_CB_HW_BLIT, pg->m_bHardwareDesktopBlit);
									SetWindowText( GetDlgItem(hwnd, IDC_CB_HW_BLIT), 
										"use hardware blit (MMX NOT PRESENT; THIS MUST BE ENABLED)");
									// note: the checkbox will be disabled @ bottom of this functino
								}

								bool bOverlay = (g_ddcaps.dwCaps & DDCAPS_OVERLAY) != 0;
								bool bDestKey = (g_ddcaps.dwCKeyCaps & DDCKEYCAPS_DESTOVERLAY) != 0;

								if (!bOverlay)
								{
									sprintf(buf, 
										"Sorry - it looks like your video card or driver\r\n"
										"doesn't meet the requirements for Desktop Mode.\r\n"
										"(reason: overlays not supported)\r\n"
										"\r\n"
										"You should change back to Windowed or Fullscreen mode\r\n"
										"before trying to run MilkDrop.");
									pg->dumpmsg(buf); 
									MessageBox( NULL, buf, "FEATURE UNAVAILABLE", MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
								}

								if (!bDestKey)
								{
									sprintf(buf, 
										"Sorry - it looks like your video card or driver\r\n"
										"doesn't meet the requirements for Desktop Mode.\r\n"
										"(reason: destination color keying not supported)\r\n"
										"\r\n"
										"You should change back to Windowed or Fullscreen mode\r\n"
										"before trying to run MilkDrop.");
									pg->dumpmsg(buf); 
									MessageBox( NULL, buf, "FEATURE UNAVAILABLE", MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
								}
							}

							Refresh(hwnd);
						}

						g_bIgnoreChanges = false;
					}
				}
				break;

			case IDC_CB_AUTOGAMMA:
				pg->m_bAutoGamma = DlgItemIsChecked(hwnd, IDC_CB_AUTOGAMMA);
				Refresh(hwnd);
				break;				

			case IDC_CB_HW_BLIT:
				pg->m_bHardwareDesktopBlit = DlgItemIsChecked(hwnd, IDC_CB_HW_BLIT);
				Refresh(hwnd);
				break;				

			case IDOK:
				
				// video mode
				ReadBitDepthCombo(hwnd);	// sets (width, height, and dispbits) if in windowed/fullscreen mode, or (pg->m_nDesktopProcSize) if in desktop mode

				// monitor selection
				t = SendMessage( GetDlgItem( hwnd, IDC_MONITORS ), CB_GETCURSEL, 0, 0);
				if (t == CB_ERR) t = 0;
				lstrcpy(pg->m_szMonitorName, g_szMonitorName[t]);
				
				// texsize
				t = SendMessage( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_GETCURSEL, 0, 0);
				if (t == CB_ERR) t = 0;
				pg->m_nTexSize	= SendMessage( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_GETITEMDATA, t, 0);

				// mesh(grid)size
				t = SendMessage( GetDlgItem( hwnd, IDC_MESHSIZECOMBO ), CB_GETCURSEL, 0, 0);
				if (t == CB_ERR) t = 0;
				pg->m_nGridX		= SendMessage( GetDlgItem( hwnd, IDC_MESHSIZECOMBO ), CB_GETITEMDATA, t, 0);

				// 16-bit-brightness slider
				t = SendMessage( GetDlgItem( hwnd, IDC_BRIGHT_SLIDER ), TBM_GETPOS, 0, 0);
				if (t != CB_ERR) pg->m_n16BitGamma = t;

				// fps limit combo box
				t = SendMessage( GetDlgItem( hwnd, IDC_MAX_FPS ), CB_GETCURSEL, 0, 0);
				if (t == CB_ERR) t = 0;
				pg->m_nFpsLimit = SendMessage( GetDlgItem( hwnd, IDC_MAX_FPS ), CB_GETITEMDATA, t, 0);

				// xbus combo boxes
				t = SendMessage( GetDlgItem( hwnd, IDC_XBUS_1 ), CB_GETCURSEL, 0, 0);
				if (t != CB_ERR) 
					pg->m_xBusMode[0] = t;
				t = SendMessage( GetDlgItem( hwnd, IDC_XBUS_2 ), CB_GETCURSEL, 0, 0);
				if (t != CB_ERR) 
					pg->m_xBusMode[1] = t;

				// checkboxes
				g_bDebugOutput = DlgItemIsChecked(hwnd, IDC_CB_DEBUGOUTPUT);
				pg->m_bShowPressF1ForHelp = (!DlgItemIsChecked(hwnd, IDC_CB_PRESSF1));
				//pg->m_bShowMenuToolTips = DlgItemIsChecked(hwnd, IDC_CB_TOOLTIPS);
				pg->m_bClearScreenAtStartup = !DlgItemIsChecked(hwnd, IDC_CB_CLS);
				pg->m_bAlways3D = DlgItemIsChecked(hwnd, IDC_CB_ALWAYS3D);
				pg->m_bFixSlowText = DlgItemIsChecked(hwnd, IDC_CB_FIXSLOWTEXT);
				pg->m_bAlwaysOnTop = DlgItemIsChecked(hwnd, IDC_CB_TOP);
				pg->m_bWarningsDisabled = DlgItemIsChecked(hwnd, IDC_CB_NOWARN);
				pg->m_bWarningsDisabled2 = DlgItemIsChecked(hwnd, IDC_CB_NOWARN2);
				
				//pg->m_bFixPinkBug = DlgItemIsChecked(hwnd, IDC_CB_PINKFIX);
				//pg->m_bWindowed = DlgItemIsChecked(hwnd, IDC_CB_WINDOWED);
				//pg->m_bDesktopMode = DlgItemIsChecked(hwnd, IDC_CB_DESKTOP);
				pg->m_bHardwareDesktopBlit = DlgItemIsChecked(hwnd, IDC_CB_HW_BLIT);
				pg->m_bEnableRating = !DlgItemIsChecked(hwnd, IDC_CB_NORATING);
				//pg->m_bDesktopModeSkipBurstCopy = DlgItemIsChecked(hwnd, IDC_CB_BURST);
				pg->m_bTryRGBOverlayFirst = DlgItemIsChecked(hwnd, IDC_CB_RGB_FIRST);
				pg->m_bTryYUY2OverlayFirst = DlgItemIsChecked(hwnd, IDC_CB_YUY2_FIRST);
				pg->m_bDesktopModeDoubleBuffered = DlgItemIsChecked(hwnd, IDC_CB_DBLBUF);
				pg->m_bAutoGamma = DlgItemIsChecked(hwnd, IDC_CB_AUTOGAMMA);
				
				pg->WriteConfig();
				EndDialog(hwnd,id);
				break;
			
			case IDCANCEL:
				EndDialog(hwnd,id);
				break;

				/*
				DialogBox( hInstance, MAKEINTRESOURCE(IDD_CONFIG2), 
					hwnd, (DLGPROC)Config2DialogProc ); 
				*/

			case IDMORE:
				DialogBox(pg->m_hDllInstance, MAKEINTRESOURCE(IDD_ADVANCED), hwnd, (DLGPROC)AdvConfigDialogProc);
				break;

			case IDTRANS:
				DialogBox(pg->m_hDllInstance, MAKEINTRESOURCE(IDD_TRANSITIONS), hwnd, (DLGPROC)TransitionConfigDialogProc);
				break;

			case IDC_FILTER_COLOR:
				
				DoColors(hwnd, &pg->m_key_R, &pg->m_key_G, &pg->m_key_B);

				/*
				CHOOSECOLOR cc;
				ZeroMemory(&cc, sizeof(CHOOSECOLOR));
				cc.lStructSize = sizeof(CHOOSECOLOR);
				cc.hwndOwner = hwnd;//NULL;//hSaverMainWindow;
				cc.Flags = CC_RGBINIT | CC_FULLOPEN;
				cc.rgbResult = RGB(pg->m_key_R, pg->m_key_G, pg->m_key_B);
				cc.lpCustColors = (LPDWORD)acrCustClr;
				if (ChooseColor(&cc))
				{
					pg->m_key_R = GetRValue(cc.rgbResult);
					pg->m_key_G = GetGValue(cc.rgbResult);
					pg->m_key_B = GetBValue(cc.rgbResult);
				}
				*/
				
				break;

			case ID_SPRITE:
				{
					char szPath[512], szFile[512];
					lstrcpy(szPath, pg->GetConfigIniFile());
					char *p = strrchr(szPath, '\\');
					if (p != NULL)
					{
						*(p+1) = 0;
						lstrcpy(szFile, szPath);
						lstrcat(szFile, "milk_img.ini");
						pg->dumpmsg("opening: (file, path)");
						pg->dumpmsg(szFile);
						pg->dumpmsg(szPath);
						int ret = (int)ShellExecute(NULL, "open", szFile, NULL, szPath, SW_SHOWNORMAL);
						if (ret <= 32)
						{
							MessageBox(hwnd, "error in ShellExecute", "error in ShellExecute", MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL);
						}
					}
				}
				break;

			case ID_MSG:
				{
					char szPath[512], szFile[512];
					lstrcpy(szPath, pg->GetConfigIniFile());
					char *p = strrchr(szPath, '\\');
					if (p != NULL)
					{
						*(p+1) = 0;
						lstrcpy(szFile, szPath);
						lstrcat(szFile, "milk_msg.ini");
						pg->dumpmsg("opening: (file, path)");
						pg->dumpmsg(szFile);
						pg->dumpmsg(szPath);
						int ret = (int)ShellExecute(NULL, "open", szFile, NULL, szPath, SW_SHOWNORMAL);
						if (ret <= 32)
						{
							MessageBox(hwnd, "error in ShellExecute", "error in ShellExecute", MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL);
						}
					}
				}
				break;

			case ID_DOCS:
				{
					char szPath[512], szFile[512];
					lstrcpy(szPath, pg->GetConfigIniFile());
					char *p = strrchr(szPath, '\\');
					if (p != NULL)
					{
						*(p+1) = 0;
						lstrcpy(szFile, szPath);
						lstrcat(szFile, "milkdrop.html");
						pg->dumpmsg("opening: (file, path)");
						pg->dumpmsg(szFile);
						pg->dumpmsg(szPath);
						int ret = (int)ShellExecute(NULL, "open", szFile, NULL, szPath, SW_SHOWNORMAL);
						if (ret <= 32)
						{
							/*
							switch(ret)
							{
							case 0: sprintf(buf, "The operating system is out of memory or resources."); break;
							case ERROR_FILE_NOT_FOUND: sprintf(buf, "ERROR_FILE_NOT_FOUND"); break;  
							case ERROR_PATH_NOT_FOUND: sprintf(buf, "ERROR_PATH_NOT_FOUND"); break;
							case ERROR_BAD_FORMAT: sprintf(buf, "ERROR_BAD_FORMAT"); break;
							default: sprintf(buf, "unknown error"); break;
							/*
							case SE_ERR_ACCESSDENIED: sprintf(buf, "SE_ERR_ACCESSDENIED"); break;
							case SE_ERR_ASSOCINCOMPLETE: sprintf(buf, "SE_ERR_ASSOCINCOMPLETE"); break;
							case SE_ERR_DDEBUSY: sprintf(buf, "SE_ERR_DDEBUSY"); break;
							case SE_ERR_DDEFAIL: sprintf(buf, "SE_ERR_DDEFAIL"); break;
							case SE_ERR_DDETIMEOUT: sprintf(buf, "SE_ERR_DDETIMEOUT"); break;
							case SE_ERR_DLLNOTFOUND: sprintf(buf, "SE_ERR_DLLNOTFOUND"); break;
							case SE_ERR_NOASSOC: sprintf(buf, "SE_ERR_NOASSOC"); break;
							case SE_ERR_OOM: sprintf(buf, "SE_ERR_OOM"); break;
							case SE_ERR_SHARE: sprintf(buf, "SE_ERR_SHARE"); break;
							*/
							//}
							MessageBox(hwnd, "error in ShellExecute", "error in ShellExecute", MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL);
						}
					}
				}
				break;

			case ID_WEB:
				{
					int ret = (int)ShellExecute(NULL, "open", "http://www.nullsoft.com/free/milkdrop", "", "", SW_SHOWNORMAL);
					if (ret <= 32)
						MessageBox(hwnd, "error in ShellExecute", "error in ShellExecute", MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL);
				}
				break;


			case ID_DEFAULTS:
				int response = MessageBox( NULL, "Are you sure you want to restore the default settings?\r\nIf you click YES, the config panel will close and the defaults will be restored.", "Restore default settings?", MB_YESNO|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL );
				if (response == IDYES)
				{
					DeleteFile(pg->GetConfigIniFile());
					Sleep(100);
					EndDialog(hwnd,id);
				}
				break;
			}
		}
		break;		// case WM_COMMAND

		/*
		For a modeless property sheet, your message loop should use 
		PSM_ISDIALOGMESSAGE to pass messages to the property sheet 
		dialog box. Your message loop should use PSM_GETCURRENTPAGEHWND 
		to determine when to destroy the dialog box. When the user clicks 
		the OK or Cancel button, PSM_GETCURRENTPAGEHWND returns NULL. 
		You can then use the DestroyWindow function to destroy the dialog box.
		*/
		

    } 
	
	return FALSE;
}








BOOL CALLBACK AdvConfigDialogProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
	char buf[256];
	char buf2[64];
	IdentifyWindowsMessage(msg, buf2);
	sprintf(buf, "AdvCfgDlgProc: hwnd=%08x, msg=%08x, wParam=%08x, lParam=%08x [%s]", hwnd, msg, wParam, lParam, buf2);
	pg->dumpmsg(buf);
	//OutputDebugString(buf);

	static int LR,LG,LB,RR,RG,RB;

	switch (msg)
	{
	case WM_NOTIFY: 
		{ 
			LPNMHDR t=(LPNMHDR)lParam; 
			if (t->code == TTN_POP) 
			{ 
				SendMessage(hTooltipWndAdv,TTM_SETDELAYTIME,TTDT_INITIAL,1000); 
				SendMessage(hTooltipWndAdv,TTM_SETDELAYTIME,TTDT_RESHOW,1000); 
			} 
		}
		break;

	case WM_DESTROY:
		if (IsWindow(hTooltipWnd)) 
		{ 
			DestroyWindow(hTooltipWndAdv); 
			hTooltipWndAdv = NULL; 
		}
		break;
	
    case WM_INITDIALOG:
		{ 
			//---------font combo boxes-------------------
			HDC hdc = GetDC(hwnd);
			if (hdc)
			{
				EnumFonts(hdc, NULL, &EnumFontsProc, (LPARAM)hwnd);
				ReleaseDC(hwnd, hdc);
			}

			for (int f=0; f<2; f++)
			{
				HWND fontbox = NULL;
				HWND sizebox = NULL;
				HWND stylebox = NULL;
				
				switch(f)
				{
				case 0:
					fontbox = GetDlgItem( hwnd, IDC_FONT );
					sizebox = GetDlgItem( hwnd, IDC_FONTSIZE );
					stylebox = GetDlgItem( hwnd, IDC_FONTOPTIONS );
					break;
				case 1:
					fontbox = GetDlgItem( hwnd, IDC_FONT2 );
					sizebox = GetDlgItem( hwnd, IDC_FONTSIZE2 );
					stylebox = GetDlgItem( hwnd, IDC_FONTOPTIONS2 );
					break;
				}

				// set selection
				int nPos = SendMessage( fontbox, CB_FINDSTRINGEXACT, -1, (LPARAM)pg->m_szFontFace[f]);
				if (nPos == CB_ERR)
					nPos = SendMessage( fontbox, CB_FINDSTRINGEXACT, -1, (LPARAM)"Monotype Corsiva");
				if (nPos != CB_ERR)
					SendMessage( fontbox, CB_SETCURSEL, nPos, 0);

				//---------font size box-------------------
				SendMessage( sizebox, CB_ADDSTRING, 0, (LPARAM)" Extra Small ");
				SendMessage( sizebox, CB_ADDSTRING, 1, (LPARAM)" Small  ");
				SendMessage( sizebox, CB_ADDSTRING, 2, (LPARAM)" Normal ");
				SendMessage( sizebox, CB_ADDSTRING, 3, (LPARAM)" Large  ");
				SendMessage( sizebox, CB_ADDSTRING, 4, (LPARAM)" Extra Large ");
				switch(pg->m_nFontSize[f])
				{
				case -2:
					SendMessage( sizebox, CB_SETCURSEL, 0, 0); break;
				case -1:
					SendMessage( sizebox, CB_SETCURSEL, 1, 0); break;
				case 0:
				default:
					SendMessage( sizebox, CB_SETCURSEL, 2, 0); break;
				case 1:
				case 2:
					SendMessage( sizebox, CB_SETCURSEL, 3, 0); break;
				case 3:
				case 4:
					SendMessage( sizebox, CB_SETCURSEL, 4, 0); break;
				}

				//---------font options box-------------------
				SendMessage( stylebox, CB_ADDSTRING, 0, (LPARAM)" None ");
				SendMessage( stylebox, CB_ADDSTRING, 1, (LPARAM)" Bold ");
				SendMessage( stylebox, CB_ADDSTRING, 2, (LPARAM)" Italic  ");
				SendMessage( stylebox, CB_ADDSTRING, 3, (LPARAM)" Bold and Italic ");
				if (pg->m_bFontBold[f] && pg->m_bFontItalic[f])
					SendMessage( stylebox, CB_SETCURSEL, 3, 0); 
				else if (pg->m_bFontItalic[f])
					SendMessage( stylebox, CB_SETCURSEL, 2, 0); 
				else if (pg->m_bFontBold[f])
					SendMessage( stylebox, CB_SETCURSEL, 1, 0); 
				else
					SendMessage( stylebox, CB_SETCURSEL, 0, 0); 
			}

			// title font:
			{
				HWND fontbox = GetDlgItem( hwnd, IDC_FONT3 );
				HWND sizebox = GetDlgItem( hwnd, IDC_FONTSIZE3 );
				HWND stylebox = GetDlgItem( hwnd, IDC_FONTOPTIONS3 );
				
				// set selection
				int nPos = SendMessage( fontbox, CB_FINDSTRINGEXACT, -1, (LPARAM)pg->m_szTitleFontFace);
				if (nPos == CB_ERR)
					nPos = SendMessage( fontbox, CB_FINDSTRINGEXACT, -1, (LPARAM)"Monotype Corsiva");
				if (nPos != CB_ERR)
					SendMessage( fontbox, CB_SETCURSEL, nPos, 0);

				//---------font size box-------------------
				SendMessage( sizebox, CB_ADDSTRING, 0, (LPARAM)" Extra Small ");
				SendMessage( sizebox, CB_ADDSTRING, 1, (LPARAM)" Small  ");
				SendMessage( sizebox, CB_ADDSTRING, 2, (LPARAM)" Normal ");
				SendMessage( sizebox, CB_ADDSTRING, 3, (LPARAM)" Large  ");
				SendMessage( sizebox, CB_ADDSTRING, 4, (LPARAM)" Extra Large ");
				SendMessage( sizebox, CB_SETCURSEL, pg->m_nTitleFontSize, 0); 
				
				//---------font options box-------------------
				SendMessage( stylebox, CB_ADDSTRING, 0, (LPARAM)" None ");
				SendMessage( stylebox, CB_ADDSTRING, 1, (LPARAM)" Bold ");
				SendMessage( stylebox, CB_ADDSTRING, 2, (LPARAM)" Italic  ");
				SendMessage( stylebox, CB_ADDSTRING, 3, (LPARAM)" Bold and Italic ");
				if (pg->m_bTitleFontBold && pg->m_bTitleFontItalic)
					SendMessage( stylebox, CB_SETCURSEL, 3, 0); 
				else if (pg->m_bTitleFontItalic)
					SendMessage( stylebox, CB_SETCURSEL, 2, 0); 
				else if (pg->m_bTitleFontBold)
					SendMessage( stylebox, CB_SETCURSEL, 1, 0); 
				else
					SendMessage( stylebox, CB_SETCURSEL, 0, 0); 
			}

			LR = pg->m_cLeftEye3DColor[0];
			LG = pg->m_cLeftEye3DColor[1];
			LB = pg->m_cLeftEye3DColor[2];
			RR = pg->m_cRightEye3DColor[0];
			RG = pg->m_cRightEye3DColor[1];
			RB = pg->m_cRightEye3DColor[2];

			sprintf(buf, " %2.1f", pg->m_fSongTitleAnimDuration);
			SetWindowText( GetDlgItem( hwnd, IDC_SONGTITLEANIM_DURATION ), buf );
			sprintf(buf, " %2.1f", pg->m_fTimeBetweenRandomSongTitles);
			SetWindowText( GetDlgItem( hwnd, IDC_RAND_TITLE             ), buf );
			sprintf(buf, " %2.1f", pg->m_fTimeBetweenRandomCustomMsgs);
			SetWindowText( GetDlgItem( hwnd, IDC_RAND_MSG               ), buf );

			CheckDlgButton(hwnd, IDC_CB_SEPTEXT, pg->m_bSeparateTextWindow);
			CheckDlgButton(hwnd, IDC_CB_TITLE_ANIMS, pg->m_bSongTitleAnims);

			//---------------------------------------------------------------

			// Initialize Tooltip window
			pg->dumpmsg("initializing tooltips...");
			int x;
			hTooltipWndAdv = CreateWindow(TOOLTIPS_CLASS,(LPCSTR)NULL,TTS_ALWAYSTIP,
				CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, hwnd,NULL,GetModuleHandle(NULL),NULL);
			SendMessage(hTooltipWndAdv,TTM_SETDELAYTIME,TTDT_AUTOPOP,5000);
			SendMessage(hTooltipWndAdv,TTM_SETDELAYTIME,TTDT_INITIAL,750);
			SendMessage(hTooltipWndAdv,TTM_SETDELAYTIME,TTDT_RESHOW,750);
			for (x = 0; x < sizeof(helpinfoAdv)/sizeof(helpinfoAdv[0]); x ++) 
			{
				TOOLINFO ti; 
				ti.cbSize = sizeof(ti); 
				ti.uFlags = TTF_SUBCLASS|TTF_IDISHWND;
				ti.uId=(unsigned int)GetDlgItem(hwnd,helpinfoAdv[x].id); 
				ti.hwnd=hwnd; 
				ti.lpszText = helpinfoAdv[x].szTip;
				SendMessage(hTooltipWndAdv,TTM_ADDTOOL,0,(LPARAM) &ti);
			}
			
			SetFocus(hwnd);

			pg->dumpmsg("---adv. config dialog init complete---");
		}
		break;		// case WM_INITDIALOG

    case WM_COMMAND:
		{
			int id = LOWORD(wParam);
			int t, f;
			float val;
			switch(id)
			{
			case IDOK:
				
				// stereo 3D colors
				pg->m_cLeftEye3DColor[0]  = LR;
				pg->m_cLeftEye3DColor[1]  = LG;
				pg->m_cLeftEye3DColor[2]  = LB;
				pg->m_cRightEye3DColor[0] = RR;
				pg->m_cRightEye3DColor[1] = RG;
				pg->m_cRightEye3DColor[2] = RB;

				// fonts
				for (f=0; f<2; f++)
				{
					HWND fontbox = GetDlgItem( hwnd, (f==0) ? IDC_FONT : IDC_FONT2 ) ;
					HWND sizebox = GetDlgItem( hwnd, (f==0) ? IDC_FONTSIZE : IDC_FONTSIZE2 ) ;
					HWND stylebox = GetDlgItem( hwnd, (f==0) ? IDC_FONTOPTIONS : IDC_FONTOPTIONS2 ) ;

					// font face
					t = SendMessage( fontbox, CB_GETCURSEL, 0, 0);
					SendMessage( fontbox, CB_GETLBTEXT, t, (LPARAM)pg->m_szFontFace[f]);
					
					// font size
					t = SendMessage( sizebox, CB_GETCURSEL, 0, 0);
					switch(t)
					{
					case 0:
						pg->m_nFontSize[f] = -2; break;
					case 1:
						pg->m_nFontSize[f] = -1; break;
					case 2:
					default:
						pg->m_nFontSize[f] = 0; break;
					case 3:
						pg->m_nFontSize[f] = 2; break;
					case 4:
						pg->m_nFontSize[f] = 4; break;
					}

					// font options
					t = SendMessage( stylebox, CB_GETCURSEL, 0, 0);
					pg->m_bFontBold[f] = ((t & 1) != 0);
					pg->m_bFontItalic[f] = ((t & 2) != 0);
				}

				// song title font
				{
					HWND fontbox = GetDlgItem( hwnd, IDC_FONT3 ) ;
					HWND sizebox = GetDlgItem( hwnd, IDC_FONTSIZE3 ) ;
					HWND stylebox = GetDlgItem( hwnd, IDC_FONTOPTIONS3 ) ;

					// font face
					t = SendMessage( fontbox, CB_GETCURSEL, 0, 0);
					SendMessage( fontbox, CB_GETLBTEXT, t, (LPARAM)pg->m_szTitleFontFace);

					// font size
					pg->m_nTitleFontSize = SendMessage( sizebox, CB_GETCURSEL, 0, 0);

					// font options
					t = SendMessage( stylebox, CB_GETCURSEL, 0, 0);
					pg->m_bTitleFontBold = ((t & 1) != 0);
					pg->m_bTitleFontItalic = ((t & 2) != 0);
				}

				// separate text window
				pg->m_bSeparateTextWindow = DlgItemIsChecked(hwnd, IDC_CB_SEPTEXT);

				GetWindowText( GetDlgItem( hwnd, IDC_SONGTITLEANIM_DURATION ), buf, sizeof(buf));
				if (sscanf(buf, "%f", &val) == 1)
					pg->m_fSongTitleAnimDuration = val;
				GetWindowText( GetDlgItem( hwnd, IDC_RAND_TITLE             ), buf, sizeof(buf));
				if (sscanf(buf, "%f", &val) == 1)
					pg->m_fTimeBetweenRandomSongTitles = val;
				GetWindowText( GetDlgItem( hwnd, IDC_RAND_MSG               ), buf, sizeof(buf));
				if (sscanf(buf, "%f", &val) == 1)
					pg->m_fTimeBetweenRandomCustomMsgs = val;

				pg->m_bSongTitleAnims = DlgItemIsChecked(hwnd, IDC_CB_TITLE_ANIMS);

				EndDialog(hwnd,id);
				break;
			
			case IDCANCEL:
				EndDialog(hwnd,id);
				break;

			case IDLEFT:
				{
					DoColors(hwnd, &LR, &LG, &LB);

					/*
					CHOOSECOLOR cc;
					ZeroMemory(&cc, sizeof(CHOOSECOLOR));
					cc.lStructSize = sizeof(CHOOSECOLOR);
					cc.hwndOwner = hwnd;//NULL;//hSaverMainWindow;
					cc.Flags = CC_RGBINIT | CC_FULLOPEN;
					cc.rgbResult = RGB(LR, LG, LB);
					cc.lpCustColors = (LPDWORD)acrCustClr;
					if (ChooseColor(&cc))
					{
						LR = GetRValue(cc.rgbResult);
						LG = GetGValue(cc.rgbResult);
						LB = GetBValue(cc.rgbResult);
					}
					*/
				}
				break;

			case IDRIGHT:
				{
					DoColors(hwnd, &RR, &RG, &RB);
					/*
					CHOOSECOLOR cc;
					ZeroMemory(&cc, sizeof(CHOOSECOLOR));
					cc.lStructSize = sizeof(CHOOSECOLOR);
					cc.hwndOwner = hwnd;//NULL;//hSaverMainWindow;
					cc.Flags = CC_RGBINIT | CC_FULLOPEN;
					cc.rgbResult = RGB(RR,RG,RB);
					cc.lpCustColors = (LPDWORD)acrCustClr;
					if (ChooseColor(&cc))
					{
						RR = GetRValue(cc.rgbResult);
						RG = GetGValue(cc.rgbResult);
						RB = GetBValue(cc.rgbResult);
					}
					*/
				}
				break;
			} // end switch(id)
		}
		break;		// case WM_COMMAND
    } 
	
	return FALSE;
}




BOOL CALLBACK TransitionConfigDialogProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
	char buf[256];
	char buf2[64];
	IdentifyWindowsMessage(msg, buf2);
	sprintf(buf, "TransCfgDlgProc: hwnd=%08x, msg=%08x, wParam=%08x, lParam=%08x [%s]", hwnd, msg, wParam, lParam, buf2);
	pg->dumpmsg(buf);
	//OutputDebugString(buf);

	switch (msg)
	{
	case WM_NOTIFY: 
		{ 
			LPNMHDR t=(LPNMHDR)lParam; 
			if (t->code == TTN_POP) 
			{ 
				SendMessage(hTooltipWndTrans,TTM_SETDELAYTIME,TTDT_INITIAL,1000); 
				SendMessage(hTooltipWndTrans,TTM_SETDELAYTIME,TTDT_RESHOW,1000); 
			} 
		}
		break;

	case WM_DESTROY:
		if (IsWindow(hTooltipWnd)) 
		{ 
			DestroyWindow(hTooltipWndTrans); 
			hTooltipWndTrans = NULL; 
		}
		break;
	
    case WM_INITDIALOG:
		{ 
			// soft cuts
			sprintf(buf, " %2.1f", pg->m_fTimeBetweenPresets);
			SetWindowText( GetDlgItem( hwnd, IDC_BETWEEN_TIME ), buf );
			sprintf(buf, " %2.1f", pg->m_fTimeBetweenPresetsRand);
			SetWindowText( GetDlgItem( hwnd, IDC_BETWEEN_TIME_RANDOM ), buf );
			sprintf(buf, " %2.1f", pg->m_fBlendTimeUser);
			SetWindowText( GetDlgItem( hwnd, IDC_BLEND_USER ), buf );
			sprintf(buf, " %2.1f", pg->m_fBlendTimeAuto);
			SetWindowText( GetDlgItem( hwnd, IDC_BLEND_AUTO ), buf );

			// hard cuts
			sprintf(buf, " %2.1f", pg->m_fHardCutHalflife);
			SetWindowText( GetDlgItem( hwnd, IDC_HARDCUT_BETWEEN_TIME ), buf );

			int n = (int)((pg->m_fHardCutLoudnessThresh - 1.25f) * 10.0f);
			if (n<0) n = 0;
			if (n>20) n = 20;
			SendMessage( GetDlgItem( hwnd, IDC_HARDCUT_LOUDNESS), TBM_SETRANGEMIN, FALSE, (LPARAM)(0) );
			SendMessage( GetDlgItem( hwnd, IDC_HARDCUT_LOUDNESS), TBM_SETRANGEMAX, FALSE, (LPARAM)(20) );
			SendMessage( GetDlgItem( hwnd, IDC_HARDCUT_LOUDNESS), TBM_SETPOS,      TRUE,  (LPARAM)(n) );

			CheckDlgButton(hwnd, IDC_CB_HARDCUTS, pg->m_bHardCutsDisabled);

			//---------------------------------------------------------------

			// Initialize Tooltip window
			pg->dumpmsg("initializing tooltips...");
			int x;
			hTooltipWndTrans = CreateWindow(TOOLTIPS_CLASS,(LPCSTR)NULL,TTS_ALWAYSTIP,
				CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, hwnd,NULL,GetModuleHandle(NULL),NULL);
			SendMessage(hTooltipWndTrans,TTM_SETDELAYTIME,TTDT_AUTOPOP,5000);
			SendMessage(hTooltipWndTrans,TTM_SETDELAYTIME,TTDT_INITIAL,750);
			SendMessage(hTooltipWndTrans,TTM_SETDELAYTIME,TTDT_RESHOW,750);
			for (x = 0; x < sizeof(helpinfoTrans)/sizeof(helpinfoTrans[0]); x ++) 
			{
				TOOLINFO ti; 
				ti.cbSize = sizeof(ti); 
				ti.uFlags = TTF_SUBCLASS|TTF_IDISHWND;
				ti.uId=(unsigned int)GetDlgItem(hwnd,helpinfoTrans[x].id); 
				ti.hwnd=hwnd; 
				ti.lpszText = helpinfoTrans[x].szTip;
				SendMessage(hTooltipWndTrans,TTM_ADDTOOL,0,(LPARAM) &ti);
			}
			
			SetFocus(hwnd);

			pg->dumpmsg("---transition config dialog init complete---");
		}
		break;		// case WM_INITDIALOG

    case WM_COMMAND:
		{
			int id = LOWORD(wParam);
			int t;
			float val;
			switch(id)
			{
			case IDOK:

				// soft cuts
				GetWindowText( GetDlgItem( hwnd, IDC_BETWEEN_TIME ), buf, sizeof(buf));
				if (sscanf(buf, "%f", &val) == 1)
					pg->m_fTimeBetweenPresets = val;
				GetWindowText( GetDlgItem( hwnd, IDC_BETWEEN_TIME_RANDOM ), buf, sizeof(buf));
				if (sscanf(buf, "%f", &val) == 1)
					pg->m_fTimeBetweenPresetsRand = val;
				GetWindowText( GetDlgItem( hwnd, IDC_BLEND_AUTO ), buf, sizeof(buf));
				if (sscanf(buf, "%f", &val) == 1)
					pg->m_fBlendTimeAuto = val;
				GetWindowText( GetDlgItem( hwnd, IDC_BLEND_USER ), buf, sizeof(buf));
				if (sscanf(buf, "%f", &val) == 1)
					pg->m_fBlendTimeUser = val;

				// hard cuts
				GetWindowText( GetDlgItem( hwnd, IDC_HARDCUT_BETWEEN_TIME ), buf, sizeof(buf));
				if (sscanf(buf, "%f", &val) == 1)
					pg->m_fHardCutHalflife = val;

				t = SendMessage( GetDlgItem( hwnd, IDC_HARDCUT_LOUDNESS ), TBM_GETPOS, 0, 0);
				if (t != CB_ERR) pg->m_fHardCutLoudnessThresh = 1.25f + t/10.0f;

				pg->m_bHardCutsDisabled = DlgItemIsChecked(hwnd, IDC_CB_HARDCUTS);
				
				EndDialog(hwnd,id);
				break;
			
			case IDCANCEL:
				EndDialog(hwnd,id);
				break;

			} // end switch(id)
		}
		break;		// case WM_COMMAND
    } 
	
	return FALSE;
}





/*
HRESULT CALLBACK D3DEnumPixelFormatsCallback(
  LPDDPIXELFORMAT lpDDPixFmt,  
  LPVOID          lpContext    
)
{
	if (lpDDPixFmt->dwFlags & DDPF_RGB)
	{
		g_texfmt[g_iNumTexFormats].bpp   = lpDDPixFmt->dwRGBBitCount;
		g_texfmt[g_iNumTexFormats].rmask = lpDDPixFmt->dwRBitMask;
		g_texfmt[g_iNumTexFormats].gmask = lpDDPixFmt->dwGBitMask;
		g_texfmt[g_iNumTexFormats].bmask = lpDDPixFmt->dwBBitMask;
		g_texfmt[g_iNumTexFormats].amask = lpDDPixFmt->dwRGBAlphaBitMask;

		char buf[256];
		sprintf(buf, "texture format: %d bits; masks: r=%08x g=%08x b=%08x a=%08x",
			g_texfmt[g_iNumTexFormats].bpp,
			g_texfmt[g_iNumTexFormats].rmask,
			g_texfmt[g_iNumTexFormats].gmask,
			g_texfmt[g_iNumTexFormats].bmask,
			g_texfmt[g_iNumTexFormats].amask);
		pg->dumpmsg(buf);

		g_iNumTexFormats++;

		if (g_iNumTexFormats == MAX_TEX_FORMATS)
		{
			pg->dumpmsg("WARNING: too many texture formats");
			return D3DENUMRET_CANCEL;
		}
	}

	return D3DENUMRET_OK;
}

bool CheckPixelFormatForTextures(LPDDSURFACEDESC2 lpDDSurfaceDesc)
{
	for (int i=0; i<g_iNumTexFormats; i++)
	{
        if (lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount == g_texfmt[i].bpp &&
			lpDDSurfaceDesc->ddpfPixelFormat.dwRBitMask == g_texfmt[i].rmask &&
			lpDDSurfaceDesc->ddpfPixelFormat.dwGBitMask == g_texfmt[i].gmask &&
			lpDDSurfaceDesc->ddpfPixelFormat.dwBBitMask == g_texfmt[i].bmask &&
			lpDDSurfaceDesc->ddpfPixelFormat.dwRGBAlphaBitMask == g_texfmt[i].amask)
		{
			return true;
		}
	}	
	return false;
}
*/


bool ConfigPanel_DirectX_Init(HWND hwnd)
{
	HRESULT		hr;
	char		buf[MAX_PATH];	
	
	/////////////////////////////////
	//  
	//            DDRAW
	//  
	/////////////////////////////////

	// 1. DirectDrawCreate
	pg->dumpmsg("calling DirectDrawCreate() for config panel...");
	//hr = DirectDrawCreate(NULL, &g_lpDD, NULL );
	hr = DirectDrawCreateEx( NULL, (void**)&g_lpDD, IID_IDirectDraw7, NULL );
	if (hr != DD_OK)
	{
		sprintf(buf, "Unable to initialize DirectDraw - you must have DirectX 7 or later installed! (DirectDrawCreateEx - %08lx)\n", hr );
		MessageBox( hwnd, buf, "MILKDROP ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
		pg->dumpmsg(buf); 
		return false;
	}

	// 2. SetCooperativeLevel
	pg->dumpmsg("calling SetCooperativeLevel() for config panel...");
	hr = g_lpDD->SetCooperativeLevel( hwnd, DDSCL_NORMAL );//EXCLUSIVE | DDSCL_FULLSCREEN );
	if (hr != DD_OK)
	{
		sprintf(buf, "Unable to set DDraw cooperative level (%08lx)\n", hr );
		MessageBox( hwnd, buf, "MILKDROP ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
		pg->dumpmsg(buf); 
		return false;
	}

	
	// NOTE: anything beyond this point only exists to get the D3D caps,
	//       so on failure, just return TRUE so that the config panel
	//       can proceed (without the d3d caps).

    // 3. GetCaps
    ZeroMemory(&g_ddcaps, sizeof(g_ddcaps));
    g_ddcaps.dwSize = sizeof(g_ddcaps);
 
	pg->dumpmsg("getting ddraw caps for config panel...");
    hr = g_lpDD->GetCaps(&g_ddcaps, NULL);
	if (hr != DD_OK)
	{
		pg->dumpmsg("  (failed! - continuing anyway)");
		return true;
	}
	else
	{
		g_bDDCapsValid = true;
	}

	// 4. create primary surface
	pg->dumpmsg("creating primary surface for config panel...");
    DDSURFACEDESC2      ddsd;
	ZeroMemory(&ddsd, sizeof(ddsd));
	ddsd.dwSize = sizeof( ddsd );
	ddsd.dwFlags = DDSD_CAPS /*| DDSD_BACKBUFFERCOUNT*/;// | DDSD_WIDTH | DDSD_HEIGHT;
	//ddsd.dwWidth  = 256;
	//ddsd.dwHeight = 256;
	ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | /*DDSCAPS_FLIP | DDSCAPS_COMPLEX |*/ DDSCAPS_3DDEVICE;// | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM; 
	/*ddsd.dwBackBufferCount = 1;*/
	
	hr = g_lpDD->CreateSurface( &ddsd, &g_lpDDSConfigFront, NULL);
	if (hr != DD_OK)
	{
		char buf[256]; sprintf(buf, "err=%08x", hr); pg->dumpmsg(buf);
		pg->dumpmsg("  (failed! - continuing anyway)");
		return true;
	}

	/*
	// 5. get a pointer to the back buffer
    DDSCAPS2            ddscaps;
	ZeroMemory(&ddscaps, sizeof(ddscaps));
	ddscaps.dwCaps = DDSCAPS_BACKBUFFER;

	pg->dumpmsg("getting pointer to backbuffer for config panel...");
	hr = g_lpDDSConfigFront->GetAttachedSurface(&ddscaps, &g_lpDDSConfigBack);
	if (hr != DD_OK)
	{
		pg->dumpmsg("couldn't get pointer to back buffer!");
		return true;
	}
	*/


	
	/////////////////////////////////
	//  
	//            D3D
	//  
	/////////////////////////////////

	// get pointer to D3D COM interface
	pg->dumpmsg("finding D3D 7 interface for config panel...");
	hr = g_lpDD->QueryInterface( IID_IDirect3D7, (VOID**)&g_lpD3D );
    if( FAILED(hr) )
    {
		pg->dumpmsg("  (failed! - continuing anyway)");
		return true;
    }

	// enumerate the D3D devices; find best device for each color depth.
	pg->dumpmsg("enumerating D3D devices for config panel...");
	ZeroMemory(&g_d3d_info, sizeof(td_checkreqs));
	hr = g_lpD3D->EnumDevices(EnumD3DDeviceCallback, &g_d3d_info);	// (see support.cpp)
    if( FAILED(hr) )
    {
		pg->dumpmsg("  (failed! - continuing anyway)");
		return true;
    }

	g_bd3d_info_valid = (g_d3d_info.b16BitOk || g_d3d_info.b24BitOk || g_d3d_info.b32BitOk);

	/*
	// create the D3D device
	pg->dumpmsg("creating D3D device for config panel...");
#ifdef _NO_HW_
	hr = g_lpD3D->CreateDevice(IID_IDirect3DRGBDevice, g_lpDDSConfigFront, &g_lpD3DDev);	// 4 choices: IID_IDirect3DTnLHalDevice, IID_IDirect3DHALDevice, IID_IDirect3DRGBDevice, IID_IDirect3DRefDevice
#else
	hr = g_lpD3D->CreateDevice(IID_IDirect3DHALDevice, g_lpDDSConfigFront, &g_lpD3DDev);	// 4 choices: IID_IDirect3DTnLHalDevice, IID_IDirect3DHALDevice, IID_IDirect3DRGBDevice, IID_IDirect3DRefDevice
#endif
	if (FAILED(hr))
	{
		pg->dumpmsg("  (failed! - continuing anyway)");

		// note: we could give them the following message, but who cares - this is a rare occurrence,
		//       and if they pick a bad video mode, it will tell them to go back and try another color
		//       depth anyway.

		//char buf[512];
		//sprintf(buf, "Note: Unable to create a D3D device.\r\n\r\nDue to this error, some Video Modes might be listed that are not actually supported.\r\n\r\nTO GET AN ACCURATE LIST OF VIDEO MODES NEXT TIME, \r\nCHANGE YOUR WINDOWS DISPLAY MODE (try a different number of color bits).\r\n\r\nClick OK to proceed to the configuration panel.");
		//MessageBox( hwnd, buf, "MILKDROP ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
		//pg->dumpmsg(buf);

		return true;
	}
	*/

	/*
	// get the caps
	pg->dumpmsg("getting d3d caps for config panel...");
	hr = g_lpD3DDev->GetCaps(&g_D3DDevDesc);
	if (FAILED(hr))
	{
		pg->dumpmsg("  (failed! - continuing anyway)");
		return true;
	}
	else
	{
		g_bD3DCapsValid = true;
		if (g_D3DDevDesc.dwDeviceRenderBitDepth & DDBD_16) pg->dumpmsg("  -D3D device supports 16-bit rendering");
		if (g_D3DDevDesc.dwDeviceRenderBitDepth & DDBD_24) pg->dumpmsg("  -D3D device supports 24-bit rendering");
		if (g_D3DDevDesc.dwDeviceRenderBitDepth & DDBD_32) pg->dumpmsg("  -D3D device supports 32-bit rendering");
	}
	*/

	/*
	// enumerate the valid texture pixelformats, so we can test them
	// vs. the video modes
	pg->dumpmsg("Enumerating texture formats...");
	g_lpD3DDev->EnumTextureFormats(&D3DEnumPixelFormatsCallback, hwnd);
	*/

	pg->dumpmsg("---DDraw and D3D setup complete.");
	return true;
}

void ConfigPanel_DirectX_Cleanup()
{

	/////////////////////////////////
	//  
	//            CLEANUP
	//  
	/////////////////////////////////

	// first D3D
	/*
	if (g_lpD3DDev)
	{
		g_lpD3DDev->Release();
		g_lpD3DDev = NULL;
	}
	*/

	if (g_lpD3D)
	{
		g_lpD3D->Release();
		g_lpD3D = NULL;
	}

	// then DDRAW
	if (g_lpDDSConfigFront)
	{
		g_lpDDSConfigFront->Release();
		g_lpDDSConfigFront = NULL;
	}

	if( g_lpDD != NULL )
	{
		g_lpDD->Release();
		g_lpDD = NULL;
	}
}